home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / snws190s.zip / HISTORY.C < prev    next >
Text File  |  1992-06-21  |  9KB  |  367 lines

  1. /*
  2.     SNEWS 1.90
  3.  
  4.     History routines
  5.  
  6.  
  7.     Copyright (C) 1991  John McCombs, Christchurch, NEW ZEALAND
  8.                         john@ahuriri.gen.nz
  9.                         PO Box 2708, Christchurch, NEW ZEALAND
  10.  
  11.     This program is free software; you can redistribute it and/or modify
  12.     it under the terms of the GNU General Public License, version 1, as
  13.     published by the Free Software Foundation.
  14.  
  15.     This program is distributed in the hope that it will be useful,
  16.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.     GNU General Public License for more details.
  19.  
  20.     See the file COPYING, which contains a copy of the GNU General
  21.     Public License.
  22.  
  23.  */
  24.  
  25.  
  26. #include "defs.h"
  27. #include "history.h"
  28. #include <alloc.h>
  29.  
  30.  
  31. FILE *hist;
  32. HIST_LIST *hlist;
  33.  
  34.  
  35. /*----------------------- open hist file for writing ------------------------*/
  36. FILE *open_hist_file(void)
  37. {
  38.     /*
  39.      *  This routine opens the history file for writing, positioned after
  40.      *  the last record.
  41.      */
  42.  
  43.     char fn[256];
  44.  
  45.     sprintf(fn, "%shistory", my_stuff.news_dir);
  46.  
  47.     if ((hist = fopen(fn, "ab")) == NULL) {
  48.         fprintf(stderr, "history: cannot open file %s for append\n", fn);
  49.         exit(1);
  50.     }
  51.  
  52.     return(hist);
  53. }
  54.  
  55.  
  56.  
  57. /*---------------------------- close hist file ---------------------------*/
  58. void close_hist_file(void)
  59. {
  60.     /*
  61.      *  This routine closes the history file
  62.      */
  63.  
  64.     fclose(hist);
  65. }
  66.  
  67.  
  68. /*---------------------------- add record -------------------------------*/
  69. void add_hist_record(char *msg_id, char *ng)
  70. {
  71.     /*
  72.      *  This routine adds a record to the history files.  It is passed the
  73.      *  message id, and the newsgroup list.  The newsgroup list is unwound,
  74.      *  and the article numbers are added to the record.
  75.      *
  76.      *  If there is only one newsgroup no history record is written
  77.      *
  78.      *  We assume that this routine is called after the article has been
  79.      *  posted, so that the article counters are correct.
  80.      */
  81.  
  82.  
  83.     char   *p, buf[512];
  84.     ACTIVE *a;
  85.     time_t t;
  86.     int    ct;
  87.  
  88.     time(&t);
  89.  
  90.     /* count the newsgroups */
  91.     strcpy(buf, ng);
  92.     p = strtok(buf, " \t,\n\r");
  93.     ct = 0;
  94.  
  95.     while (p != NULL) {
  96.         ct++;
  97.         p = strtok(NULL, " \t,\n\r");
  98.     }
  99.  
  100.  
  101.     if (ct > 1) {
  102.  
  103.         strcpy(buf, ng);
  104.         p = strtok(buf, " \t,\n\r");
  105.  
  106.         if ((p != NULL) && (strlen(msg_id) > 0)) {
  107.  
  108.             fprintf(hist, "%s %09ld ", msg_id, t);
  109.  
  110.             while (p != NULL) {
  111.                 a = find_news_group(p);
  112.                 fprintf(hist, "%s %08ld  ", a->group, a->hi_num);
  113.                 p = strtok(NULL, " \t,\n\r");
  114.             }
  115.             fprintf(hist, "\n");
  116.         }
  117.     }
  118. }
  119.  
  120.  
  121.  
  122.  
  123.  
  124. /*--------------------- read history file into ram -------------------------*/
  125. HIST_LIST *load_history_list(void)
  126. {
  127.     /*
  128.      *  This routine opens and reads the history file, building and index
  129.      *
  130.      *  Load this after active and ng files.  Set HIST_MEM_LIMIT in defs.h
  131.      *  to ensure there is enough memory left
  132.      */
  133.  
  134.     char      buf[512], *p;
  135.     long      where;
  136.     HIST_LIST *h;
  137.  
  138.     sprintf(buf, "%shistory", my_stuff.news_dir);
  139.  
  140.     /* open the file */
  141.     if ((hist = fopen(buf, "rb")) == NULL) {
  142.         fprintf(stderr, "history: cannot open file %s for reading\n", buf);
  143.         exit(1);
  144.     }
  145.  
  146.     where = 0;
  147.     hlist = NULL;
  148.  
  149.     while (fgets(buf, 511, hist)) {
  150.  
  151.         p = strtok(buf, " \t\n\r");
  152.  
  153.         if (hlist == NULL) {
  154.             hlist = xmalloc(sizeof(HIST_LIST));
  155.             h = hlist;
  156.         } else {
  157.             h->next = xmalloc(sizeof(HIST_LIST));
  158.             h = h->next;
  159.         }
  160.  
  161.         h->mid = hash_msg_id(p);
  162.         h->offset = where;
  163.  
  164.         /* leave some memory for other things */
  165.         if (farcoreleft() < HIST_MEM_LIMIT) break;
  166.  
  167.  
  168.         where = ftell(hist);
  169.     }
  170.  
  171.     h->next = NULL;
  172.  
  173.     return(hlist);
  174. }
  175.  
  176.  
  177.  
  178.  
  179. /*------------------------- release the history list ----------------------*/
  180. void free_hist_list(void)
  181. {
  182.     /*
  183.      *  Close the history file and free the memory list
  184.      */
  185.     HIST_LIST *h;
  186.  
  187.     close_hist_file();
  188.  
  189.     while (hlist != NULL) {
  190.         h = hlist->next;
  191.         free(hlist);
  192.         hlist = h;
  193.     }
  194. }
  195.  
  196.  
  197.  
  198.  
  199. /*-------------------------- find history entry -----------------------------*/
  200. HIST_LIST *find_msg_id(char *msg_id)
  201. {
  202.     /*
  203.      *  Look up the history list and return the entry for the req'd msg id
  204.      *  or NULL if not found.
  205.      */
  206.  
  207.     HIST_LIST *h;
  208.     long      hashed_id;
  209.  
  210.     hashed_id = hash_msg_id(msg_id);
  211.     h = hlist;
  212.  
  213.     while (h != NULL) {
  214.         if (h->mid == hashed_id) break;
  215.     }
  216.  
  217.     if (h->mid == hashed_id)
  218.         return(h);
  219.     else
  220.         return(NULL);
  221. }
  222.  
  223.  
  224.  
  225.  
  226. /*----------------------- lookup cross posts --------------------------------*/
  227. CROSS_POSTS *look_up_history(char *msg_id, char *ng)
  228. {
  229.     /*
  230.      *  This routine returns a linked list of the groups to which
  231.      *  an article has been crossposted.  Self is excluded.  To do
  232.      *  this we:
  233.      *      - hash the msg id
  234.      *      - search the list of id's
  235.      *      - if a hit is found we read it from the hist file
  236.      *      - decode the record, excluding self
  237.      *      - build a CROSS_POSTS list
  238.      *
  239.      *  NULL is returned if there were no crossposts.  ASSUMES global
  240.      *  file 'hist' is open.  If it isn't this routine always returns
  241.      *  NULL
  242.      */
  243.  
  244.     long        hid;
  245.     HIST_LIST   *h;
  246.     CROSS_POSTS *cx, *c;
  247.     char        buf[512], *p;
  248.  
  249.     hid = hash_msg_id(msg_id);
  250.  
  251.     /* look for the crosspost entry */
  252.     h = hlist;
  253.     while (h != NULL) {
  254.         if (h->mid == hid) break;
  255.         h = h->next;
  256.     }
  257.  
  258.     /* now look up the history file */
  259.     cx = NULL;
  260.     if (h->mid == hid) {
  261.         fseek(hist, h->offset, SEEK_SET);
  262.         if (fgets(buf, 511, hist) != NULL) {
  263.  
  264.             /*
  265.              *  Compare the target msg id with the one on the file.  If they
  266.              *  are different then the must be a hash collision - just abort
  267.              */
  268.             p = strtok(buf, " \t\n\r");
  269.             if (stricmp(p, msg_id) == 0) {
  270.  
  271.  
  272.                 /* skip the date field and leave pointiing to the first group */
  273.                 p = strtok(NULL, " \t\n\r");
  274.                 p = strtok(NULL, " \t\n\r");
  275.  
  276.                 while (p != NULL) {
  277.  
  278.                     /* exclude self */
  279.                     if (stricmp(p, ng) != 0) {
  280.                         if (cx == NULL) {
  281.                             cx = xmalloc(sizeof(CROSS_POSTS));
  282.                             c = cx;
  283.                         } else {
  284.                             c->next = xmalloc(sizeof(CROSS_POSTS));
  285.                             c = c->next;
  286.                         }
  287.  
  288.                         strcpy(c->group, p);
  289.                         p = strtok(NULL, " \t\n\r");
  290.                         c->art_num = atol(p);
  291.  
  292.                     } else {
  293.                         /* eat article number */
  294.                         p = strtok(NULL, " \t\n\r");
  295.                     }
  296.  
  297.                     c->next = NULL;
  298.  
  299.                     p = strtok(NULL, " \t\n\r");
  300.                 }
  301.  
  302.             }
  303.         }
  304.     }
  305.  
  306.     return(cx);
  307.  
  308. }
  309.  
  310.  
  311.  
  312. /*----------------------- deallocate crosspost list --------------------------*/
  313. void free_cross_post_list(CROSS_POSTS *cx)
  314. {
  315.     CROSS_POSTS *c;
  316.  
  317.     while (cx != NULL) {
  318.         c = cx->next;
  319.         free(cx);
  320.         cx = c;
  321.     }
  322.  
  323. }
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330. /*------------------------ random number generator -------------------------*/
  331. long seed;
  332.  
  333. long xrand(void)
  334. {
  335.     seed = (seed * 16807) & 0x7FFFFFFFL;
  336.     return( seed );
  337. }
  338.  
  339.  
  340.  
  341. /*----------------------------- hash a key -----------------------------------*/
  342. long hash_key(long s, char *key)
  343. {
  344.     long hash_num;
  345.     int  i;
  346.  
  347.     hash_num = 0;
  348.     seed = s;
  349.  
  350.     for (i = 0; i < strlen(key); i++) {
  351.         hash_num += xrand() * (key[i] + 0xFF00);
  352.     }
  353.  
  354.     hash_num = hash_num & 0x7FFFFFFFL;
  355.     if (hash_num == 0) hash_num++;
  356.  
  357.     return(hash_num);
  358. }
  359.  
  360.  
  361. /*----------------------------- hash the message id -------------------------*/
  362. long hash_msg_id(char *msg_id)
  363. {
  364.  
  365.     return( hash_key(hash_key(26l, msg_id), msg_id) );
  366. }
  367.